#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>

// 8.接受、发送数据bufferevent_read() / bufferevent_write()
// 读缓冲区回调
void read_cb(struct bufferevent *bev, void *arg){
    char buf[1024] = {0};

    bufferevent_read(bev, buf, sizeof(buf));
    printf("client say: %s\n", buf);

    char *p = "我是服务器，已经成功收到你发送的数据!";

    //写数据给客户端
    bufferevent_write(bev, p, strlen(p) + 1);
    sleep(1);
    return;
}

// 写缓冲区回调
void write_cb(struct bufferevent *bev, void *arg){
    printf("I'm服务器,成功写数据给客户端,写缓冲区回调函数被回调...\n");
    return;
}

// 事件回调
void event_cb(struct bufferevent *bev, short events, void *arg){
    if(events & BEV_EVENT_EOF){
        printf("connection closed\n");
    }
    else if(events & BEV_EVENT_ERROR){
        printf("some other error\n");
    }
    bufferevent_free(bev);
    printf("buffevent 资源已经被释放...\n");
    return;
}

// 3.在evconnlistener_new_bind()的回调函数中,处理接收连接后的操作;
// 4.回调函数被调用,说明有一个新客户端连接上来,会得到一个新的fd,用于跟客户端通信(读、写);
void cb_listener(struct evconnlistener *listenerr, evutil_socket_t fd, struct sockaddr *addr, int len, void *ptr){

    printf("connect new client\n");

    struct event_base *base = (struct event_base*)ptr;
    
    // 5.使用bufferevent_socket_new()创建一个新bufferevent事件,将fd封装到这个事件对象中
    struct bufferevent *bev;
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

    // 6.使用bufferevent_setcb()给这个事件对象的read、write、event设置回调
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);

    // 7.设置bufferevent的读写缓冲区enable/disable
    bufferevent_enable(bev, EV_READ);

    return;
}

int main(int argc, char *argv[]){
    // init server
    struct sockaddr_in serv;

    memset(&serv, 0, sizeof(struct sockaddr_in));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);

    // 1.创建 event_base
    struct event_base* base;
    base = event_base_new();

    // 2.创建服务器连接监听器 evconnlistener_new_bind()
    // 创建套接字 socket
    // 绑定 bin
    // 接收连接请求 accept
    struct evconnlistener* listener;  // 监听器
    listener = evconnlistener_new_bind(base, cb_listener, base, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
                                       36, (struct sockaddr*)&serv, sizeof(serv));
    
    // 9.启动循环监听
    event_base_dispatch(base);

    // 10.释放资源
    evconnlistener_free(listener);
    event_base_free(base);

    return 0;
}